/**
 * 严肃声明：
 * 开源版本请务必保留此注释头信息，若删除我方将保留所有法律责任追究！
 * 本软件已申请软件著作权，受国家版权局知识产权以及国家计算机软件著作权保护！
 * 可正常分享和学习源码，不得用于违法犯罪活动，违者必究！
 * Copyright (c) 2019-2021 十三 all rights reserved.
 * 版权所有，侵权必究！
 */
package ltd.newbee.mall.service.impl;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import ltd.newbee.mall.api.admin.param.GrantPointParam;
import ltd.newbee.mall.api.mall.param.MallUserUpdateParam;
import ltd.newbee.mall.common.Constants;
import ltd.newbee.mall.common.NewBeeMallException;
import ltd.newbee.mall.common.ServiceResultEnum;
import ltd.newbee.mall.dao.MallUserMapper;
import ltd.newbee.mall.dao.MallUserPointMapper;
import ltd.newbee.mall.dao.NewBeeMallOrderMapper;
import ltd.newbee.mall.dao.NewBeeMallUserTokenMapper;
import ltd.newbee.mall.entity.MallUser;
import ltd.newbee.mall.entity.MallUserPointConsume;
import ltd.newbee.mall.entity.MallUserPointGrant;
import ltd.newbee.mall.entity.MallUserToken;
import ltd.newbee.mall.entity.NewBeeMallOrder;
import ltd.newbee.mall.service.NewBeeMallUserService;
import ltd.newbee.mall.util.DateUtil;
import ltd.newbee.mall.util.MD5Util;
import ltd.newbee.mall.util.NumberUtil;
import ltd.newbee.mall.util.PageQueryUtil;
import ltd.newbee.mall.util.PageResult;
import ltd.newbee.mall.util.Result;
import ltd.newbee.mall.util.ResultGenerator;
import ltd.newbee.mall.util.StringUtil;
import ltd.newbee.mall.util.SystemUtil;

@Service
public class NewBeeMallUserServiceImpl implements NewBeeMallUserService {
    private static final Logger LOGGER = LoggerFactory.getLogger(NewBeeMallUserServiceImpl.class);
    @Autowired
    private MallUserMapper mallUserMapper;
    @Autowired
    private NewBeeMallUserTokenMapper newBeeMallUserTokenMapper;
    @Autowired
    private MallUserPointMapper pointMapper;
    @Autowired
    private NewBeeMallOrderMapper orderMapper;

    @Override
    public String register(String loginName, String password) {
        if (mallUserMapper.selectByLoginName(loginName) != null) {
            return ServiceResultEnum.SAME_LOGIN_NAME_EXIST.getResult();
        }
        MallUser registerUser = new MallUser();
        registerUser.setLoginName(loginName);
        registerUser.setNickName(loginName);
        registerUser.setIntroduceSign(Constants.USER_INTRO);
        String passwordMD5 = MD5Util.MD5Encode(password, "UTF-8");
        registerUser.setPasswordMd5(passwordMD5);
        if (mallUserMapper.insertSelective(registerUser) > 0) {
            return ServiceResultEnum.SUCCESS.getResult();
        }
        return ServiceResultEnum.DB_ERROR.getResult();
    }

    @Override
    public String login(String loginName, String passwordMD5) {
        MallUser user = mallUserMapper.selectByLoginNameAndPasswd(loginName, passwordMD5);
        if (user != null) {
            if (user.getLockedFlag() == 1) {
                return ServiceResultEnum.LOGIN_USER_LOCKED_ERROR.getResult();
            }
            // 登录后即执行修改token的操作
            String token = getNewToken(System.currentTimeMillis() + "", user.getUserId());
            MallUserToken mallUserToken = newBeeMallUserTokenMapper.selectByPrimaryKey(user.getUserId());
            // 当前时间
            Date now = new Date();
            // 过期时间
            Date expireTime = new Date(now.getTime() + 2 * 24 * 3600 * 1000); // 过期时间 48 小时
            if (mallUserToken == null) {
                mallUserToken = new MallUserToken();
                mallUserToken.setUserId(user.getUserId());
                mallUserToken.setToken(token);
                mallUserToken.setUpdateTime(now);
                mallUserToken.setExpireTime(expireTime);
                // 新增一条token数据
                if (newBeeMallUserTokenMapper.insertSelective(mallUserToken) > 0) {
                    // 新增成功后返回
                    return token;
                }
            } else {
                mallUserToken.setToken(token);
                mallUserToken.setUpdateTime(now);
                mallUserToken.setExpireTime(expireTime);
                // 更新
                if (newBeeMallUserTokenMapper.updateByPrimaryKeySelective(mallUserToken) > 0) {
                    // 修改成功后返回
                    return token;
                }
            }

        }
        return ServiceResultEnum.LOGIN_ERROR.getResult();
    }

    /**
     * 获取token值
     * @param timeStr
     * @param userId
     * @return
     */
    private String getNewToken(String timeStr, Long userId) {
        String src = timeStr + userId + NumberUtil.genRandomNum(4);
        return SystemUtil.genToken(src);
    }

    @Override
    public Boolean updateUserInfo(MallUserUpdateParam mallUser, Long userId) {
        MallUser user = mallUserMapper.selectByPrimaryKey(userId);
        if (user == null) {
            NewBeeMallException.fail(ServiceResultEnum.DATA_NOT_EXIST.getResult());
        }
        user.setNickName(mallUser.getNickName());
        // user.setPasswordMd5(mallUser.getPasswordMd5());
        // 若密码为空字符，则表明用户不打算修改密码，使用原密码保存
        if (!MD5Util.MD5Encode("", "UTF-8").equals(mallUser.getPasswordMd5())) {
            user.setPasswordMd5(mallUser.getPasswordMd5());
        }
        user.setIntroduceSign(mallUser.getIntroduceSign());
        if (mallUserMapper.updateByPrimaryKeySelective(user) > 0) {
            return true;
        }
        return false;
    }

    @Override
    public Boolean logout(Long userId) {
        return newBeeMallUserTokenMapper.deleteByPrimaryKey(userId) > 0;
    }

    @Override
    public PageResult getNewBeeMallUsersPage(PageQueryUtil pageUtil) {
        List<MallUser> mallUsers = mallUserMapper.findMallUserList(pageUtil);
        int total = mallUserMapper.getTotalMallUsers(pageUtil);
        PageResult pageResult = new PageResult(mallUsers, total, pageUtil.getLimit(), pageUtil.getPage());
        return pageResult;
    }

    @Override
    @Transactional
    public Result pointGrant(GrantPointParam grantPointParam, Long adminUserId) {
        MallUser mallUser = mallUserMapper.selectByPrimaryKey(grantPointParam.getUserId());
        if (mallUser == null) {
            return ResultGenerator.genFailResult("用户不存在");
        }
        MallUserPointGrant grant = new MallUserPointGrant();
        grant.setCreateBy(adminUserId);
        grant.setUpdateBy(adminUserId);
        grant.setCreateTime(new Date());
        grant.setUpdateTime(new Date());
        grant.setUserId(grantPointParam.getUserId());
        grant.setPoint(new BigDecimal(grantPointParam.getPoint()));
        Date startTime = StringUtil.isEmpty(grantPointParam.getStartTime()) ? new Date()
                : (grantPointParam.getStartTime().length() < 14 ? DateUtil.dateParse(grantPointParam.getStartTime().substring(0, 8) + "000000", DateUtil.SHORT_DATE_TIME_PATTERN)
                        : DateUtil.dateParse(grantPointParam.getStartTime().substring(0, 14), DateUtil.SHORT_DATE_TIME_PATTERN));
        Date endTime = StringUtil.isEmpty(grantPointParam.getEndTime()) ? new Date()
                : (grantPointParam.getEndTime().length() < 14 ? DateUtil.dateParse(grantPointParam.getEndTime().substring(0, 8) + "000000", DateUtil.SHORT_DATE_TIME_PATTERN)
                        : DateUtil.dateParse(grantPointParam.getEndTime().substring(0, 14), DateUtil.SHORT_DATE_TIME_PATTERN));
        grant.setStartTime(startTime);
        grant.setEndTime(endTime);
        grant.setIsDeleted(0);
        pointMapper.insertGrant(grant);
        // 更新用户记录表? 只管发放
        mallUserMapper.updateAddPoint(grantPointParam.getUserId(), new BigDecimal(grantPointParam.getPoint()));
        return ResultGenerator.genSuccessResult("积分分配成功");
    }

    @Override
    @Transactional
    public Result pointGrantCancellation(Long grantId, Long adminUserId) {
        MallUserPointGrant grant = pointMapper.getGrantById(grantId);
        if (grant == null || grant.getIsDeleted() > 0) {
            return ResultGenerator.genFailResult("积分授权记录不存在");
        }
        pointMapper.deleteGrant(grantId, adminUserId);
        pointMapper.deleteConsume(grantId, 2); // 积分发放删除 此处隐藏
        // 重新计算账户积分
        BigDecimal point = getUsablePoint(grant.getUserId());
        mallUserMapper.updatePoint(grant.getUserId(), point); // 修改账户体系中的金额
        return ResultGenerator.genSuccessResult("取消授权成功");
    }

    @Override
    @Transactional
    public Result pointAdminGrantRecord(Integer pageNum, Integer pageSize) {
        if (pageNum == null || pageNum < 1) {
            pageNum = 1;
        }
        if (pageSize == null || pageSize < 10) {
            pageSize = 10;
        }
        Integer start = (pageNum - 1) * pageSize;
        List<MallUserPointGrant> grantList = pointMapper.getGrantListByAdmin(start, pageSize);
        for (int i = 0; i < grantList.size(); i++) {
            MallUserPointGrant pointGrant = grantList.get(i);
            BigDecimal consumeMoney = pointMapper.getGrantConsumeSum(pointGrant.getGrantId());
            pointGrant.setUsePoint(consumeMoney);
            MallUser mallUser = mallUserMapper.selectByPrimaryKey(pointGrant.getUserId());
            if (mallUser != null) {
                pointGrant.setNickName(mallUser.getNickName());
            }
        }
        PageResult pageResult = new PageResult(grantList, pointMapper.countGrantListByAdmin(), pageSize, pageNum);
        return ResultGenerator.genSuccessResult(pageResult);
    }

    private BigDecimal getUsablePoint(Long userId) {
        BigDecimal grantAmount = pointMapper.getGrantSum(userId);
        BigDecimal consumeAmount = pointMapper.getConsumeSum(userId);
        BigDecimal point = grantAmount.subtract(consumeAmount);
        if (point.compareTo(new BigDecimal(0)) <= 0) {
            point = new BigDecimal("0.0000");
        }
        return point;
    }

    public static BigDecimal centToYuan(BigDecimal cent) {
        if (cent == null) {
            cent = new BigDecimal(0);
        }
        return cent.divide(new BigDecimal("100"));
    }

    @Override
    @Transactional
    public Result userConsumePoint(Long userId, String orderNo) {
        MallUser mallUser = mallUserMapper.selectByPrimaryKey(userId);
        if (mallUser == null) {
            return ResultGenerator.genFailResult("用户不存在");
        }

        NewBeeMallOrder order = orderMapper.selectByOrderNo(orderNo);
        if (order == null) {
            return ResultGenerator.genFailResult("订单不存在");
        }
        if (order.getPayStatus() != 0) {
            return ResultGenerator.genFailResult("订单状态不是可支付");
        }
        if (order.getTotalPrice() < 1) {
            return ResultGenerator.genFailResult("订单支付金额错误");
        }
        BigDecimal consumePoint = centToYuan(BigDecimal.valueOf(order.getTotalPrice())); // 订单和商品是分
        // 查询可用积分
        BigDecimal usablePoint = getUsablePoint(userId);
        if (usablePoint.compareTo(new BigDecimal(0)) <= 0) {
            return ResultGenerator.genFailResult("暂无可用积分");
        }
        if (usablePoint.compareTo(consumePoint) <= 0) {
            return ResultGenerator.genFailResult("积分不足");
        }
        BigDecimal residueDeduction = consumePoint; // 剩余可抵扣
        // 获取所有可用积分列表
        List<MallUserPointGrant> grantList = pointMapper.getUserAllGrant(userId);
        if (grantList == null || grantList.size() < 1) {
            return ResultGenerator.genFailResult("暂无可用积分规则");
        }
        for (int i = 0; i < grantList.size(); i++) {
            MallUserPointGrant grant = grantList.get(i);
            // 获取当前积分发放规则消耗了多少
            BigDecimal sendPoint = grant.getPoint();
            BigDecimal consumeAlready = pointMapper.getUserConsumeSum(grant.getGrantId());
            if (sendPoint.compareTo(consumeAlready) <= 0) { // 已全部消耗,进下次循环
                continue;
            }
            BigDecimal residue = sendPoint.subtract(consumeAlready); // 剩余
            BigDecimal current = new BigDecimal(0); // 本次抵扣
            if (residue.compareTo(residueDeduction) <= 0) { // 剩余可扣多
                residueDeduction = residueDeduction.subtract(residue);
                current = residue;
            } else {
                current = residueDeduction;
                residueDeduction = new BigDecimal(0);
            }
            // 创建消费记录
            MallUserPointConsume consume = new MallUserPointConsume();
            consume.setCreateTime(new Date());
            consume.setUpdateTime(new Date());
            consume.setGrantId(grant.getGrantId());
            consume.setIsDeleted(0);
            consume.setOrderNo(orderNo);
            consume.setPoint(current); // 本次消费
            consume.setUserId(userId);
            pointMapper.insertConsume(consume);
            if (residueDeduction.compareTo(new BigDecimal(0)) <= 0) { // 跳出循环 处理完成
                mallUserMapper.updateSubtractPoint(grant.getUserId(), consumePoint); // 修改账户体系中的金额
                break;
            }
        }
        if (residueDeduction.compareTo(BigDecimal.ZERO) >= 0) {
            throw new RuntimeException("积分支付失败，积分实时不同步");
        } else {
            int updateSize = orderMapper.orderPaySuccess(orderNo, 1, 1, 3);
            if (updateSize < 1) {
                throw new RuntimeException("积分支付失败，订单更新失败");
            }
        }
        return ResultGenerator.genSuccessResult("消费成功");
    }

    @Override
    public Result userPointExpire(Date expireDate) {
        List<MallUserPointGrant> grantList = pointMapper.queryExpireGrant(expireDate);
        LOGGER.info("userPointExpire本次作废{}条", grantList.size());
        pointMapper.expireGrant(expireDate); // 批量作废
        for (int i = 0; i < grantList.size(); i++) {
            MallUserPointGrant grant = grantList.get(i);
            pointMapper.expireConsume(grant.getGrantId());
        }
        return ResultGenerator.genSuccessResult("积分发放作废成功");
    }

    @Override
    public Boolean lockUsers(Long[] ids, int lockStatus) {
        if (ids.length < 1) {
            return false;
        }
        return mallUserMapper.lockUserBatch(ids, lockStatus) > 0;
    }

}
